Coverage Report

Created: 2024-12-19 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
D:\a\tools.proto\tools.proto\compiler\src\compiler\message.rs
Line
Count
Source
1
// Copyright (c) 2024, BlockProject 3D
2
//
3
// All rights reserved.
4
//
5
// Redistribution and use in source and binary forms, with or without modification,
6
// are permitted provided that the following conditions are met:
7
//
8
//     * Redistributions of source code must retain the above copyright notice,
9
//       this list of conditions and the following disclaimer.
10
//     * Redistributions in binary form must reproduce the above copyright notice,
11
//       this list of conditions and the following disclaimer in the documentation
12
//       and/or other materials provided with the distribution.
13
//     * Neither the name of BlockProject 3D nor the names of its contributors
14
//       may be used to endorse or promote products derived from this software
15
//       without specific prior written permission.
16
//
17
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29
use crate::compiler::error::Error;
30
use crate::compiler::structure::{FixedFieldType, Structure};
31
use crate::compiler::union::Union;
32
use crate::compiler::util::store::name_index;
33
use crate::compiler::util::types::{Name, PtrKey};
34
use crate::compiler::Protocol;
35
use crate::model::message::MessageFieldValue;
36
use crate::model::protocol::{Description, Endianness};
37
use crate::model::structure::StructFieldRaw;
38
use bp3d_debug::{error, trace};
39
use std::cell::Cell;
40
use std::fmt::{Display, Formatter};
41
use std::rc::Rc;
42
use crate::compiler::builder::FieldBuilder;
43
44
#[derive(Clone, Debug)]
45
pub enum Referenced {
46
    Struct(Rc<Structure>),
47
    Message(Rc<Message>),
48
}
49
50
impl Name for Referenced {
51
32
    fn name(&self) -> &str {
52
32
        match self {
53
24
            Referenced::Struct(v) => &v.name,
54
8
            Referenced::Message(v) => &v.name,
55
        }
56
32
    }
57
}
58
59
impl PtrKey for Referenced {
60
63
    fn ptr_key(&self) -> usize {
61
63
        match self {
62
54
            Referenced::Struct(v) => v.ptr_key(),
63
9
            Referenced::Message(v) => v.ptr_key(),
64
        }
65
63
    }
66
}
67
68
impl Referenced {
69
58
    pub fn lookup(proto: &Protocol, reference_name: &str) -> Option<Self> {
70
58
        proto
71
58
            .structs
72
58
            .get(reference_name)
73
58
            .map(|v| 
Referenced::Struct(v.clone())39
)
74
58
            .or_else(|| 
proto.messages.get(reference_name).map(19
|v|
Referenced::Message(v.clone())19
)19
)
75
58
    }
76
}
77
78
#[derive(Clone, Debug)]
79
pub struct FixedContainerField {
80
    pub ty: FixedFieldType,
81
    pub item_type: Rc<Structure>,
82
}
83
84
impl Display for FixedContainerField {
85
10
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
86
10
        write!(f, "FixedContainer<{}, Len = {}>", self.item_type.name, self.ty)
87
10
    }
88
}
89
90
#[derive(Clone, Debug)]
91
pub struct SizedBufferField {
92
    pub ty: FixedFieldType,
93
}
94
95
impl Display for SizedBufferField {
96
8
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
97
8
        write!(f, "Varbuf<{}>", self.ty)
98
8
    }
99
}
100
101
#[derive(Clone, Debug)]
102
pub struct ContainerField {
103
    pub ty: FixedFieldType,
104
    pub item_type: Rc<Message>,
105
    pub nested: bool,
106
}
107
108
impl Display for ContainerField {
109
21
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
110
21
        write!(f, "Container<{}, Len = {}>", self.item_type.name(), self.ty)
111
21
    }
112
}
113
114
#[derive(Clone, Debug)]
115
pub struct SizedContainerField {
116
    pub ty: FixedFieldType,
117
    pub item_type: Rc<Message>,
118
    pub size_ty: FixedFieldType,
119
}
120
121
impl Display for SizedContainerField {
122
7
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
123
7
        write!(
124
7
            f,
125
7
            "SizedContainer<{}, Len = {}, Size = {}>",
126
7
            self.item_type.name(),
127
7
            self.ty,
128
7
            self.size_ty
129
7
        )
130
7
    }
131
}
132
133
#[derive(Clone, Debug)]
134
pub struct FixedField {
135
    pub ty: FixedFieldType,
136
}
137
138
impl Display for FixedField {
139
8
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
140
8
        write!(f, "{}", self.ty)
141
8
    }
142
}
143
144
#[derive(Clone, Debug)]
145
pub struct UnionField {
146
    pub r: Rc<Union>,
147
}
148
149
impl Display for UnionField {
150
8
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
151
8
        f.write_str(self.r.name())
152
8
    }
153
}
154
155
#[derive(Clone, Debug)]
156
pub enum FieldType {
157
    Fixed(FixedField),
158
    Ref(Referenced),
159
160
    /// A buffer field is a field which has a known size which can be determined at runtime
161
    /// (ex: a null-terminated string).
162
    Buffer,
163
164
    /// A sized buffer field is a field which has a known size field based on a configurable type
165
    /// (ex: a Varchar).
166
    SizedBuffer(SizedBufferField),
167
168
    /// A fixed container is a container which can store only fixed size elements (structures).
169
    FixedContainer(FixedContainerField),
170
171
    Union(UnionField),
172
173
    /// A container can store dynamically sized elements.
174
    Container(ContainerField),
175
176
    /// A container which has an additional configurable size field to detect the size in bytes of
177
    /// the container.
178
    SizedContainer(SizedContainerField),
179
180
    Payload,
181
}
182
183
impl Display for FieldType {
184
106
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
185
106
        match self {
186
8
            FieldType::Fixed(v) => v.fmt(f),
187
24
            FieldType::Ref(v) => f.write_str(v.name()),
188
20
            FieldType::Buffer => f.write_str("Buffer"),
189
8
            FieldType::SizedBuffer(v) => v.fmt(f),
190
10
            FieldType::FixedContainer(v) => v.fmt(f),
191
8
            FieldType::Union(v) => v.fmt(f),
192
21
            FieldType::Container(v) => v.fmt(f),
193
7
            FieldType::SizedContainer(v) => v.fmt(f),
194
0
            FieldType::Payload => f.write_str("Bytes"),
195
        }
196
106
    }
197
}
198
199
impl FieldType {
200
49
    pub fn is_message_reference(&self) -> bool {
201
49
        match self {
202
12
            FieldType::Ref(v) => match v {
203
9
                Referenced::Struct(_) => false,
204
3
                Referenced::Message(_) => true,
205
            },
206
37
            _ => false,
207
        }
208
49
    }
209
210
19
    pub fn is_union(&self) -> bool {
211
19
        
matches!6
(self, FieldType::Union(_))
212
19
    }
213
214
53
    pub fn is_string(&self) -> bool {
215
53
        
matches!35
(self, FieldType::SizedBuffer(_) | FieldType::Buffer)
216
53
    }
217
}
218
219
#[derive(Copy, Clone, Debug)]
220
pub struct SizeInfo {
221
    pub is_dyn_sized: bool,
222
    pub is_element_dyn_sized: bool,
223
}
224
225
#[derive(Clone, Debug)]
226
pub struct HeaderField {
227
    pub name: String,
228
    pub index: usize,
229
}
230
231
impl HeaderField {
232
62
    fn from_model(header: Option<String>, fields: &[Field]) -> Result<(Option<Self>, Option<&Field>), Error> {
233
62
        match header {
234
10
            Some(header) => {
235
10
                let (
index, field9
) = fields
236
10
                    .iter()
237
10
                    .enumerate()
238
10
                    .find_map(|(k, v)| 
if v.name == header9
{
Some((k, v))9
} else {
None0
}9
)
  Branch (238:43): [True: 9, False: 0]
  Branch (238:43): [Folded - Ignored]
239
10
                    .ok_or(Error::UndefinedReference(header))
?1
;
240
9
                let header = HeaderField {
241
9
                    index,
242
9
                    name: field.name.clone()
243
9
                };
244
9
                Ok((Some(header), Some(field)))
245
            }
246
52
            None => Ok((None, None)),
247
        }
248
62
    }
249
}
250
251
#[derive(Clone, Debug)]
252
pub struct Field {
253
    pub name: String,
254
    pub header: Option<HeaderField>,
255
    pub ty: FieldType,
256
    pub optional: bool,
257
    pub size: SizeInfo,
258
    pub endianness: Endianness,
259
    pub description: Option<Description>,
260
    pub codec: Option<String>,
261
}
262
263
impl Display for Field {
264
106
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
265
106
        match (self.optional, &self.codec) {
266
4
            (true, None) => write!(f, "{}: {}?, {} endian", self.name, self.ty, self.endianness),
267
36
            (false, None) => write!(f, "{}: {}, {} endian", self.name, self.ty, self.endianness),
268
11
            (true, Some(v)) => write!(f, "{}: {} ({})?, {} endian", self.name, v, self.ty, self.endianness),
269
55
            (false, Some(v)) => write!(f, "{}: {} ({}), {} endian", self.name, v, self.ty, self.endianness)
270
        }
271
106
    }
272
}
273
274
impl Field {
275
227
    pub fn codec(&self) -> &str {
276
227
        self.codec.as_deref().unwrap_or("base")
277
227
    }
278
279
64
    fn from_model(
280
64
        proto: &Protocol,
281
64
        unsorted: &[Field],
282
64
        has_headers: bool,
283
64
        value: crate::model::message::MessageField,
284
64
    ) -> Result<Self, Error> {
285
64
        if (value.value.is_none() && 
value.item_type.is_none()16
) || (
value.value.is_some()63
&&
value.item_type.is_some()48
)
  Branch (285:13): [True: 16, False: 48]
  Branch (285:38): [True: 1, False: 15]
  Branch (285:69): [True: 48, False: 15]
  Branch (285:94): [True: 1, False: 47]
  Branch (285:13): [Folded - Ignored]
  Branch (285:38): [Folded - Ignored]
  Branch (285:69): [Folded - Ignored]
  Branch (285:94): [Folded - Ignored]
286
        {
287
2
            return Err(Error::BadFieldType);
288
62
        }
289
62
        let (
header, header_field61
) = HeaderField::from_model(value.header, unsorted)
?1
;
290
61
        if let Some(
field9
) = header_field {
  Branch (290:16): [True: 9, False: 52]
  Branch (290:16): [Folded - Ignored]
291
8
            match &field.ty {
292
8
                FieldType::Ref(Referenced::Struct(v)) => v.set_used_in_header(),
293
1
                v => {
294
1
                    error!("Invalid header field type, expected struct reference, got field type {:?}", v);
295
1
                    return Err(Error::InvalidHeaderType);
296
                }
297
            }
298
52
        }
299
60
        let builder = FieldBuilder::new(value.name, value.optional.unwrap_or_default(), proto.endianness)
300
60
            .description(value.description).header(header).codec(value.codec);
301
60
        if let Some(
info45
) = value.value {
  Branch (301:16): [True: 45, False: 15]
  Branch (301:16): [Folded - Ignored]
302
45
            match info {
303
                MessageFieldValue::List {
304
16
                    max_len,
305
16
                    item_type,
306
16
                    max_size,
307
16
                    nested,
308
16
                } => {
309
16
                    if max_len == 0 {
  Branch (309:24): [True: 1, False: 15]
  Branch (309:24): [Folded - Ignored]
310
1
                        return Err(Error::ZeroArray);
311
15
                    }
312
15
                    if builder.has_codec() {
  Branch (312:24): [True: 0, False: 15]
  Branch (312:24): [Folded - Ignored]
313
0
                        return Err(Error::ForbiddenCodec(builder.name().into()));
314
15
                    }
315
15
                    let r = Referenced::lookup(proto, &item_type).ok_or(Error::UndefinedReference(item_type))
?0
;
316
15
                    let ty = FixedFieldType::from_max_value(max_len)
?0
;
317
15
                    match r {
318
4
                        Referenced::Struct(item_type) => Ok(builder.codec(Some("list".into())).build(FieldType::FixedContainer(FixedContainerField { item_type, ty }))),
319
11
                        Referenced::Message(item_type) => {
320
11
                            if let Some(
max_size3
) = max_size {
  Branch (320:36): [True: 3, False: 8]
  Branch (320:36): [Folded - Ignored]
321
3
                                if max_size == 0 {
  Branch (321:36): [True: 1, False: 2]
  Branch (321:36): [Folded - Ignored]
322
1
                                    return Err(Error::ZeroArray);
323
2
                                }
324
2
                                let size_ty = FixedFieldType::from_max_value(max_size)
?0
;
325
2
                                Ok(
326
2
                                    builder
327
2
                                        .codec(Some("list".into()))
328
2
                                        .size_info(SizeInfo {
329
2
                                            is_element_dyn_sized: false,
330
2
                                            is_dyn_sized: true
331
2
                                        })
332
2
                                        .build(FieldType::SizedContainer(SizedContainerField { ty, item_type, size_ty }))
333
2
                                )
334
                            } else {
335
8
                                item_type.embedded.set(true);
336
8
                                Ok(
337
8
                                    builder
338
8
                                        .codec(Some("list".into()))
339
8
                                        .dynamic_size()
340
8
                                        .build(FieldType::Container(ContainerField {
341
8
                                            ty,
342
8
                                            item_type,
343
8
                                            nested: nested.unwrap_or_default(),
344
8
                                        }))
345
8
                                )
346
                            }
347
                        }
348
                    }
349
                },
350
                MessageFieldValue::Container {
351
2
                    max_len,
352
2
                    item_type,
353
2
                    max_size,
354
2
                    nested,
355
2
                } => {
356
2
                    if max_len == 0 {
  Branch (356:24): [True: 0, False: 2]
  Branch (356:24): [Folded - Ignored]
357
0
                        return Err(Error::ZeroArray);
358
2
                    }
359
2
                    let r = Referenced::lookup(proto, &item_type).ok_or(Error::UndefinedReference(item_type))
?0
;
360
2
                    let ty = FixedFieldType::from_max_value(max_len)
?0
;
361
2
                    match r {
362
0
                        Referenced::Struct(item_type) => Ok(builder.build(FieldType::FixedContainer(FixedContainerField { item_type, ty }))),
363
2
                        Referenced::Message(item_type) => {
364
2
                            if let Some(
max_size1
) = max_size {
  Branch (364:36): [True: 1, False: 1]
  Branch (364:36): [Folded - Ignored]
365
1
                                if max_size == 0 {
  Branch (365:36): [True: 0, False: 1]
  Branch (365:36): [Folded - Ignored]
366
0
                                    return Err(Error::ZeroArray);
367
1
                                }
368
1
                                let size_ty = FixedFieldType::from_max_value(max_size)
?0
;
369
1
                                Ok(
370
1
                                    builder
371
1
                                        .size_info(SizeInfo {
372
1
                                            is_element_dyn_sized: false,
373
1
                                            is_dyn_sized: true
374
1
                                        })
375
1
                                        .build(FieldType::SizedContainer(SizedContainerField { ty, item_type, size_ty }))
376
1
                                )
377
                            } else {
378
1
                                item_type.embedded.set(true);
379
1
                                Ok(
380
1
                                    builder
381
1
                                        .dynamic_size()
382
1
                                        .build(FieldType::Container(ContainerField {
383
1
                                            ty,
384
1
                                            item_type,
385
1
                                            nested: nested.unwrap_or_default(),
386
1
                                        }))
387
1
                                )
388
                            }
389
                        }
390
                    }
391
                },
392
14
                MessageFieldValue::String { max_len } => {
393
14
                    if builder.has_codec() {
  Branch (393:24): [True: 0, False: 14]
  Branch (393:24): [Folded - Ignored]
394
0
                        return Err(Error::ForbiddenCodec(builder.name().into()));
395
14
                    }
396
14
                    match max_len {
397
10
                        None => Ok(builder.codec(Some("string".into())).build(FieldType::Buffer)),
398
4
                        Some(max_len) => {
399
4
                            if max_len == 0 {
  Branch (399:32): [True: 1, False: 3]
  Branch (399:32): [Folded - Ignored]
400
1
                                return Err(Error::ZeroArray);
401
3
                            }
402
3
                            let ty = FixedFieldType::from_max_value(max_len)
?0
;
403
3
                            Ok(builder.codec(Some("string".into())).build(FieldType::SizedBuffer(SizedBufferField { ty })))
404
                        }
405
                    }
406
                },
407
2
                MessageFieldValue::Buffer { max_len } => {
408
2
                    match max_len {
409
0
                        None => Ok(builder.build(FieldType::Buffer)),
410
2
                        Some(max_len) => {
411
2
                            if max_len == 0 {
  Branch (411:32): [True: 0, False: 2]
  Branch (411:32): [Folded - Ignored]
412
0
                                return Err(Error::ZeroArray);
413
2
                            }
414
2
                            let ty = FixedFieldType::from_max_value(max_len)
?0
;
415
2
                            Ok(builder.build(FieldType::SizedBuffer(SizedBufferField { ty })))
416
                        }
417
                    }
418
                },
419
7
                MessageFieldValue::Union { name } => {
420
7
                    let 
r6
= proto.unions.get(&name).ok_or(Error::UndefinedReference(name))
?1
;
421
6
                    let 
header_field5
= header_field.ok_or(Error::MissingHeaderForUnion)
?1
;
422
5
                    match &header_field.ty {
423
5
                        FieldType::Ref(Referenced::Struct(v)) => {
424
5
                            if !Rc::ptr_eq(&r.discriminant.root, v) {
  Branch (424:32): [True: 1, False: 4]
  Branch (424:32): [Folded - Ignored]
425
1
                                error!(
426
1
                                    "Union discriminant type mismatch, expected {}, got {}",
427
1
                                    v.name, r.discriminant.root.name
428
1
                                );
429
1
                                return Err(Error::UnionTypeMismatch);
430
4
                            }
431
                        },
432
0
                        _ => unreachable!()
433
                    }
434
4
                    if value.optional.unwrap_or_default() {
  Branch (434:24): [True: 0, False: 4]
  Branch (434:24): [Folded - Ignored]
435
0
                        eprintln!("WARNING: ignoring unsupported optional flag on union message field!");
436
4
                    }
437
4
                    Ok(builder.size_info(r.size).build(FieldType::Union(UnionField { r: r.clone() })))
438
                }
439
0
                MessageFieldValue::Payload => Ok(builder.dynamic_size().build(FieldType::Payload)),
440
4
                MessageFieldValue::Unsigned { bits } => {
441
4
                    let ty = FixedFieldType::from_model(StructFieldRaw::Unsigned { bits })
?0
;
442
4
                    Ok(builder.fixed_size().build(FieldType::Fixed(FixedField { ty })))
443
                }
444
            }
445
        } else {
446
15
            let item_type = unsafe { value.item_type.unwrap_unchecked() };
447
15
            let r = Referenced::lookup(proto, &item_type).ok_or(Error::UndefinedReference(item_type))
?0
;
448
15
            match r {
449
13
                Referenced::Struct(r) => {
450
13
                    let is_single = r.fields.len() == 1;
451
13
                    let is_fixed = r.fields[0].ty.as_fixed().is_some();
452
13
                    let is_none = r.fields[0].ty.as_fixed().map(|v| v.raw.is_none()).unwrap_or_default();
453
13
                    let is_byte_aligned = r.fields[0].loc.bit_size % 8 == 0;
454
13
                    trace!({has_headers} {is_single} {is_fixed} {is_none} {is_byte_aligned}, "Found struct reference: {}", r.name);
455
13
                    if !has_headers && 
is_single6
&&
is_fixed2
&&
is_none2
&&
is_byte_aligned2
{
  Branch (455:24): [True: 6, False: 7]
  Branch (455:40): [True: 2, False: 4]
  Branch (455:53): [True: 2, False: 0]
  Branch (455:65): [True: 2, False: 0]
  Branch (455:76): [True: 2, False: 0]
  Branch (455:24): [Folded - Ignored]
  Branch (455:40): [Folded - Ignored]
  Branch (455:53): [Folded - Ignored]
  Branch (455:65): [Folded - Ignored]
  Branch (455:76): [Folded - Ignored]
456
2
                        let fixed = unsafe { r.fields[0].ty.as_fixed().unwrap_unchecked() };
457
2
                        Ok(builder.fixed_size().build(FieldType::Fixed(FixedField { ty: fixed.bits_type })))
458
                    } else {
459
11
                        Ok(builder.fixed_size().build(FieldType::Ref(Referenced::Struct(r))))
460
                    }
461
                }
462
2
                Referenced::Message(r) => Ok(builder.size_info(r.size).build(FieldType::Ref(Referenced::Message(r))))
463
            }
464
        }
465
64
    }
466
}
467
468
#[derive(Clone, Debug)]
469
pub struct Message {
470
    pub name: String,
471
    pub description: Option<Description>,
472
    pub fields: Vec<Field>,
473
    pub size: SizeInfo,
474
    embedded: Cell<bool>,
475
}
476
477
impl Message {
478
28
    pub(crate) fn is_embedded(&self) -> bool {
479
28
        self.embedded.get()
480
28
    }
481
482
39
    pub fn from_model(proto: &Protocol, value: crate::model::message::Message) -> Result<Message, Error> {
483
39
        let mut fields = Vec::with_capacity(value.fields.len());
484
39
        let mut dyn_sized_elem_count = 0;
485
39
        let mut is_dyn_sized = false;
486
63
        let has_headers = value.fields.iter().any(|v| v.header.is_some()
)39
;
487
93
        for 
v64
in value.fields {
488
64
            let 
field54
= Field::from_model(proto, &fields, has_headers, v)
?10
;
489
54
            if field.size.is_dyn_sized {
  Branch (489:16): [True: 37, False: 17]
  Branch (489:16): [Folded - Ignored]
490
37
                is_dyn_sized = true;
491
37
            
}17
492
54
            if dyn_sized_elem_count > 0 && (
field.size.is_dyn_sized0
||
field.size.is_element_dyn_sized0
) {
  Branch (492:16): [True: 0, False: 54]
  Branch (492:45): [True: 0, False: 0]
  Branch (492:72): [True: 0, False: 0]
  Branch (492:16): [Folded - Ignored]
  Branch (492:45): [Folded - Ignored]
  Branch (492:72): [Folded - Ignored]
493
0
                return Err(Error::VarsizeAfterPayload);
494
54
            }
495
54
            if field.size.is_element_dyn_sized {
  Branch (495:16): [True: 9, False: 45]
  Branch (495:16): [Folded - Ignored]
496
9
                dyn_sized_elem_count += 1;
497
45
            }
498
54
            if dyn_sized_elem_count > 1 {
  Branch (498:16): [True: 0, False: 54]
  Branch (498:16): [Folded - Ignored]
499
0
                return Err(Error::MultiPayload);
500
54
            }
501
54
            fields.push(field);
502
        }
503
29
        Ok(Message {
504
29
            name: value.name,
505
29
            description: value.description,
506
29
            fields,
507
29
            size: SizeInfo {
508
29
                is_dyn_sized,
509
29
                is_element_dyn_sized: dyn_sized_elem_count > 0,
510
29
            },
511
29
            embedded: Cell::new(false),
512
29
        })
513
39
    }
514
}
515
516
name_index!(Message => name);